﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.Windows.Controls.Primitives;

namespace HugeFlow.CommandPattern.Interactivity
{
    public enum KeyTriggerFiredOn
    {
        KeyDown,
        KeyUp
    }

    public class KeyTrigger : EventTriggerBase<UIElement>
    {
        #region Properties

        // Fields
        public static readonly DependencyProperty FiredOnProperty = DependencyProperty.Register("FiredOn", typeof(KeyTriggerFiredOn), typeof(KeyTrigger), null);
        public static readonly DependencyProperty KeyProperty = DependencyProperty.Register("Key", typeof(Key), typeof(KeyTrigger), null);
        public static readonly DependencyProperty ModifiersProperty = DependencyProperty.Register("Modifiers", typeof(ModifierKeys), typeof(KeyTrigger), null);
        private UIElement targetElement;

        /// <summary>
        /// 키 down 혹은 up
        /// </summary>
        public KeyTriggerFiredOn FiredOn
        {
            get
            {
                return (KeyTriggerFiredOn)base.GetValue(FiredOnProperty);
            }
            set
            {
                base.SetValue(FiredOnProperty, value);
            }
        }

        /// <summary>
        /// 키
        /// </summary>
        public Key Key
        {
            get
            {
                return (Key)base.GetValue(KeyProperty);
            }
            set
            {
                base.SetValue(KeyProperty, value);
            }
        }

        /// <summary>
        /// 기능 키
        /// </summary>
        public ModifierKeys Modifiers
        {
            get
            {
                return (ModifierKeys)base.GetValue(ModifiersProperty);
            }
            set
            {
                base.SetValue(ModifiersProperty, value);
            }
        }

        #endregion Properties

        #region Methods

        // Methods
        private static ModifierKeys GetActualModifiers(Key key, ModifierKeys modifiers)
        {
            if (key == Key.Ctrl)
            {
                modifiers |= ModifierKeys.Control;
                return modifiers;
            }
            if (key == Key.Alt)
            {
                modifiers |= ModifierKeys.Alt;
                return modifiers;
            }
            if (key == Key.Shift)
            {
                modifiers |= ModifierKeys.Shift;
            }
            return modifiers;
        }

        protected override string GetEventName()
        {
            return "Loaded";
        }

        private static UIElement GetRoot(DependencyObject current)
        {
            UIElement element = null;
            while (current != null)
            {
                element = current as UIElement;
                current = VisualTreeHelper.GetParent(current);
            }
            return element;
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            if (this.targetElement != null)
            {
                if (this.FiredOn == KeyTriggerFiredOn.KeyDown)
                {
                    this.targetElement.KeyDown += new KeyEventHandler(this.OnKeyPress);
                }
                else
                {
                    this.targetElement.KeyUp += new KeyEventHandler(this.OnKeyPress);
                }
            }
        }

        protected override void OnSourceChanged(UIElement oldSource, UIElement newSource)
        {
            base.OnSourceChanged(oldSource, newSource);

            this.targetElement = newSource;
            OnAttached();
        }

        protected override void OnDetaching()
        {
            if (this.targetElement != null)
            {
                if (this.FiredOn == KeyTriggerFiredOn.KeyDown)
                {
                    this.targetElement.KeyDown -= new KeyEventHandler(this.OnKeyPress);
                }
                else
                {
                    this.targetElement.KeyUp -= new KeyEventHandler(this.OnKeyPress);
                }
            }
            base.OnDetaching();
        }

        private void OnKeyPress(object sender, KeyEventArgs e)
        {
            if ((e.Key == this.Key) && (Keyboard.Modifiers == GetActualModifiers(e.Key, this.Modifiers)))
            {
                base.InvokeActions(e);
            }
        }

        #endregion Methods
    }
}
